/*
  spa.shell.js
  shell setting
*/

/*jslint
  bowser : true, continue : true,
  devel : true, indent : 2, maxerr : 50,
  newcap : true, nomen : true, plusplus : true,
  regexp : true, sloppy : true, vars : false,
  white: true
*/

spa.shell = (function() {
  /*                 module variable start                       */
  var configMap = {
    anchor_schema_map : {
      modal : { 
        article : true, login: true, 
        search: true,   deactivated : true,
        signup: true
      },
      _modal :{
        id: true
      },
      memo : {
        activate : true,
        deactivated : true
      },
      _memo : {
        loadlist : true                 
      },
      category : {
        politics : true,  society : true,
        economy : true,   global : true,
        science : true,   culture : true,
        sports : true,    deactivated: true,
      },
      _category: {
        page: true
      }
    },
    main_html : String()
      + '<div class="spa-shell-head">'
        + '<div class="spa-shell-head-logo">Article RSS Reader</div>'
        + '<div class="spa-shell-head-detailed spa-shell-button">자세히</div>'
        + '<div class="spa-shell-head-acct spa-shell-button">'
          + '<img src="images/magnifier.svg" />'
        + '</div>'
        + '<div class="spa-shell-head-search"><input class="spa-shell-search-input" type="text" /></div>'
        + '<div class="spa-shell-head-login spa-shell-button">로그인</div>'
      + '</div>'
      + '<div class="spa-shell-main">'
        + '<div class="spa-shell-main-nav"></div>'
        + '<div class="spa-shell-main-content"></div>'
      + '</div>'
      + '<div class="spa-shell-foot">'
        + '<div class="spa-shell-memo"></div>'
      + '</div>'
      + '<div class="spa-shell-search_modal spa-shell-modal"></div>'
      + '<div class="spa-shell-article_modal spa-shell-modal"></div>'
      + '<div class="spa-shell-login_modal spa-shell-modal"></div>'
      + '<div class="spa-shell-signup_modal spa-shell-modal"></div>'
      + '<div class="spa-shell-wrap"></div>'
      ,
      modal_activate_wrap_opacity : 0.5,
      modal_deactivate_wrap_opacity : 0.0,
      modal_activate_opacity : 1.0,
      modal_deactivate_opacity : 0.0,
      modal_activate_time : 300,
      modal_deactivate_time : 300
  },
  stateMap = {
    $container : null,
    is_modal_activate : true,
    is_slide_activate : true,
    anchor_map : {},
    $activated_modal : null,
    login_user : null,
  },
  jqueryMap = {},

  copyAnchorMap,          setJqueryMap,       initModule, 
  onDetailedButtonClick,  onAcctButtonClick,  onLoginButtonClick,
  onModalWrapClick,       modalActivate,      changeAnchorPart,
  onHashChange,           isModalActivated,   onMemoTitleClick,
  onSignupButtonClick,    loginCheck,         onCategoryClick,
  onSearchButtonClick;
  /*                    module variable end                 */

  /*                    utility method start                  */
  // /copyAnchorMap/ Start
  // 목적   : 현재 앵커 맵을 복사하여 반환
  // 반환값 : anchor_map 개체
  copyAnchorMap = function() {
    return $.extend(true, {}, stateMap.anchor_map);
  }
  // /copyAnchorMap/ End
  /*                    utility method end                   */

  /*                     DOM method start                              */
  // /setJqueryMap/ start
  setJqueryMap = function() {
    var $container = stateMap.$container;
    jqueryMap = {
      $container : $container,
      $search_modal : $container.find('.spa-shell-search_modal'),
      $article_modal : $container.find('.spa-shell-article_modal'),
      $login_modal : $container.find('.spa-shell-login_modal'),
      $modal_wrap : $container.find('.spa-shell-wrap')
    };
  };
  // /setJqueryMap/ end
  
  // /toggleModalActivate/ start
  // 목적   : 모달 팝업을 열거나 닫음.
  // 
  // 인자   :
  //          - $modal : 활성, 비활성화 시킬 모달 제이쿼리 개체.
  //          - do_activate : true면 활성화시키고 false면 비활성화시킴.
  //          - callback : 애니메이션 종료 시점에서 실행할 callback 함수.
  //
  // 상태   : stateMap.is_modal_activate 값을 설정.
  //          - true : 모달 팝업이 활성화된 상태.
  //          - false : 모달 팝업이 비활성화된 상태.
  // 
  // 반환값 : boolean
  //          - true : 모달 팝업의 활성화 혹은 비활성화가 이상없이 완료됨.
  //          - false : 실행 과정에서 오류가 발생하였음.
  toggleModalActivate = function($modal, do_activate, callback) {
    var modal_opacity = jqueryMap.$modal_wrap.css("opacity"),
        is_activated = modal_opacity === configMap.modal_activate_wrap_opacity;
    
    if (!$modal) {return false;}

    // 모달 팝업을 활성화시키는 작업 시작
    if (do_activate) {
      if (stateMap.is_modal_activate === false) { // 이미 활성화된 모달 팝업이 있다면 비활성화시킨다.
        stateMap.$activated_modal.hide();
      }
      $modal.show().animate(
          {opacity : configMap.modal_activate_opacity},
          configMap.modal_activate_time,
          function() {
            stateMap.is_modal_activate = false;
            stateMap.$activated_modal = $modal;
          }
      );
      jqueryMap.$modal_wrap.show().animate(
          {opacity : configMap.modal_activate_wrap_opacity},
          configMap.modal_activate_time,
          function() {
            jqueryMap.$modal_wrap.on('click', {$target: $modal},onModalWrapClick);
            if (callback) {callback($modal)}
          }
      );
      return true;
    } // 모달 팝업을 활성화 시키는 작업 끝
    // 모달 팝업을 비활성화 시키는 작업 시작
    else {
      $modal.animate(
          {opacity : configMap.modal_deactivate_opacity},
          configMap.modal_deactivate_time,
          function() {
            stateMap.is_modal_activate = true;
            stateMap.$activated_modal = null;
            $(this).hide();
          }
      );
      jqueryMap.$modal_wrap.animate(
          {opacity : configMap.modal_deactivate_wrap_opacity},
          configMap.modal_deactivate_time,
          function() {
            $(this).hide();
            jqueryMap.$modal_wrap.off('click', onModalWrapClick);
            if (callback) {callback($modal)}
          }
      );
      return true;
    }
    // 모달 팝업을 비활성화 시키는 작업 끝
  };
  // /toggleModalActivate/ end 

  // /changeAnchorPart/ start
  // 목적   : URI 앵커 컴포넌트의 일부 영역 변경
  // 인자   :
  //          - arg_map : URI 앵커 중 변경할 부분을 나타내는 맵
  // 반환값 : boolean
  //          - true : URI의 앵커부분이 변경됨.
  //          - false : URI의 앵커부분이 변경되지 않음.
  // 행동   : 현재 앵커는 stateMap.anchor_map에 저장되어있음.
  //          인코딩 방식은 uriAnchor을 참고하고,
  //          이 메서드의 알고리즘은
  //          1. copyAnchorMap()을 사용해 맵을 복사한다.
  //          2. arg_map을 사용해서 키-값을 수정한다.
  //          3. 인코딩 과정에서 독립적인 값과 의존적인 값을 서로 구분한다.
  //          4. uriAnchor을 활용해서 URI 변경을 시도한다.
  //          5. 성공 시에는 true, 실패 시에는 false를 반환한다.
  changeAnchorPart = function(arg_map) {
    var anchor_map_revise = copyAnchorMap(), // 지금 현재의 앵커 맵을 복사해온다.
        bool_return = true,
        key_name, key_name_dep;

    // 변경 사항을 앵커 맵으로 합치는 작업 시작
    KEYVAL:
    for (key_name in arg_map) {
      if (arg_map.hasOwnProperty(key_name)) {

        // 루프 중 의존적 키는 넘어감.
        if (key_name.indexOf('_') === 0) {continue KEYVAL;}
        
        // 독립적 키 값을 업데이트.
        anchor_map_revise[key_name] = arg_map[key_name];

        // 대응되는 의존적 키를 업데이트.
        key_name_dep = '_' + key_name;
        if (arg_map[key_name_dep]) {
          anchor_map_revise[key_name_dep] = arg_map[key_name_dep];
        }
        else {
          delete anchor_map_revise[key_name_dep];
          delete anchor_map_revise['_s' + key_name_dep];
        }
      }
    }
    // 변경 사항을 앵커 맵으로 합치는 작업 끝

    // URI 업데이트를 시도. 과정 중에 에러가 발생하면 원래의 엥커 맵으로 복원.
    try {
      $.uriAnchor.setAnchor(anchor_map_revise);
    }
    catch (error) {
      $.uriAnchor.setAnchor(stateMap.anchor_map, null, true);
      bool_return = false;
    }
    //URI 업데이트 시도 끝.
  };
  // /changeAnchorPart/ end
  // /loginCheck/ Start
  loginCheck = function() {
    var request = $.ajax({
      type : "POST",
      url : "jsp/getSessionInfo.jsp",
      dataType : "json",
      data : "",
      success : function(response) {
        if (response.result !== null) {
          $('.spa-shell-head-login').html('로그아웃')
          .off("click").on("click", function() {
            $.ajax({
              type : "POST",
              url : "jsp/Logout.jsp",
              success : function(response) {
                alert("로그아웃 되었습니다.");
                $(location).attr('href', 'index.html');
              }
            });  
          });
        }
      },
    });
  };
  // /loginCheck/ End
  /*                           DOM method end                             */

  /*                         Event handler start                        */
  // /onDetailedButtonClick/ Start
  onDetailedButtonClick = function(e) {
    changeAnchorPart({
      modal: (stateMap.is_modal_activate ? "search" : "deactivated")
    });
    return false;
  };
  // /onDetailedButtonClick/ End
  // /onAcctButtonClick/ Start
  onAcctButtonClick = function(e) {
    return false;
  };
  // /onAcctButtonClick/ End
  // /onLoginButtonClick/ Start
  onLoginButtonClick = function(e) {
    changeAnchorPart({
      modal: (stateMap.is_modal_activate ? "login" : "deactivated")
    });
    return false;
  };
  // /onLoginButtonClick/ End
  // /onModalWrapClick/ Start
  onModalWrapClick = function(e) {
    changeAnchorPart({
      modal: "deactivated"
    });
    return false;
  };
  // /onModalWrapClick/ End
  // /onMemoTitleClick/ Start
  onMemoTitleClick = function(e) {
    changeAnchorPart({
      memo: ( spa.memo.getIsMemoSlide() ? "activate" : "deactivated")
    });
    return false;
  };
  // /onMemoTitleClick/ End
  // /onSignupButtonClick/ Start 
  onSignupButtonClick = function(e) {
    changeAnchorPart( {
      modal: "signup" 
    });
    return false;
  }
  onCategoryClick = function( category_id ) {
    var category_name;
    switch( category_id ){
      case 1:
        category_name = "politics";
        break;
      case 2:
        category_name = "society";
        break;
      case 3:
        category_name = "economy";
        break;
      case 4:
        category_name = "global";
        break;
      case 5:
        category_name = "science";
        break;
      case 6:
        category_name = "culture";
        break;
      case 7:
        category_name = "sports";
        break;
      default:
        category_name = "deactivated";
    }
    changeAnchorPart({
      category : category_name
    });
  }
  // /onSignupButtonClick/ End
  // /onSearchButtonClick/ Start
  onSearchButtonClick = function( e ) {
    var search_word = $('.spa-shell-search-input').val();
    spa.model.article.getList(null, null, search_word);
  };
  // /onSearchButtonClick/ End
  // /onHashChange/ Start
  // 목적   : hashchange 이벤트 핸들링
  // 인자   : - e : 제이쿼리 이벤트 객체
  // 상태   : anchor_map 업데이트
  // 반환값 : false
  // 행동   :
  //          1. URI 앵커 컴포넌트를 파싱
  //          2. 파싱된 애플리케이션 상태를 현재 상태와 비교
  //          3. 현재 상태와 다를 때에만 애플리케이션의 상태를 변경
  onHashChange = function(e) {
    var anchor_map_previous = copyAnchorMap(),
        anchor_map_proposed,
        s_modal_previous,   s_modal_proposed,
        s_memo_previous,    s_memo_proposed;

    // 앵커 파싱을 시도
    try {
      anchor_map_proposed = $.uriAnchor.makeAnchorMap();
    }
    catch(error) {
      $.uriAnchor.setAnchor(anchor_map_previous, null, true);
      return false;
    }
    // 앵커 파싱을 성공하면 현재 앵커 맵 상태 업데이트
    stateMap.anchor_map = anchor_map_proposed;
    
    // 모달 파트 시작
    s_modal_previous = anchor_map_previous.modal;
    s_modal_proposed = anchor_map_proposed.modal;

    // 앵커 맵이 아예 없는 상태이거나 모달의 상태가 다를 때만 행동
    if (!anchor_map_previous || (s_modal_previous !== s_modal_proposed)) {
      switch(s_modal_proposed) {
        case "search":
          toggleModalActivate($('.spa-shell-search_modal'), true);
          break;
        case "article":
          //spa.view.renderArticle(testModel[anchor_map_proposed._modal.id]);
          var request = spa.model.article.getArticle(anchor_map_proposed._modal.id);
          request.success(function(response) {
            spa.view.renderArticle(response);
            toggleModalActivate($('.spa-shell-article_modal'), true);
          });
          break;
        case "login":
          toggleModalActivate($('.spa-shell-login_modal'), true);
          break;
        case "signup":
          toggleModalActivate($('.spa-shell-signup_modal'), true);
          break;
        case "deactivated":
          toggleModalActivate(stateMap.$activated_modal, false);
          break;
        default:
          toggleModalActivate(stateMap.$activated_modal, false);
          delete anchor_map_proposed.modal;
          setTimeout(function() {  
            $.uriAnchor.setAnchor(anchor_map_proposed, null, true);
          }, configMap.modal_deactivate_time);
      }
    }
    // 모달 파트 끝
    
    // 메모 파트 시작
    s_memo_previous = anchor_map_previous.memo;
    s_memo_proposed = anchor_map_proposed.memo;
    
    if (!anchor_map_previous || (s_memo_previous !== s_memo_proposed)) {
      switch( s_memo_proposed ) {
        case "activate":
          spa.memo.slideToggle( true );
          break;
        case "deactivated":
          spa.memo.slideToggle( false );
          break;
        default:
          spa.memo.slideToggle( false );
          delete anchor_map_proposed.memo;
          $.uriAnchor.setAnchor( anchor_map_proposed, null, true);
      }
    }
    // 메모 파트 끝
    // 카테고리 파트 시작
    var s_category_previous = anchor_map_previous.category,
        s_category_proposed = anchor_map_proposed.category;

    if (!anchor_map_previous || s_category_previous !== s_category_proposed) {
    switch( s_category_proposed ){
      case "politics":
        spa.model.article.getList(null, 1);
        break;
      case "society":
        spa.model.article.getList(null, 2);
        break;
      case "economy":
        spa.model.article.getList(null, 3);
        break;
      case "global":
        spa.model.article.getList(null, 4);
        break;
      case "science":
        spa.model.article.getList(null, 5);
        break;
      case "culture":
        spa.model.article.getList(null, 6);
        break;
      case "sports":
        spa.model.article.getList(null, 7);
        break;
      default:
        spa.model.article.getList(null, null);
        $.uriAnchor.setAnchor( anchor_map_proposed, null, true);
    }
    }
  };
  // /onHashChange/ End
  /*                           Event handler end                             */

  /*                           Public method start                           */
  // /initModule/ Start
  initModule = function($container) {
    stateMap.$container = $container;
    $container.html(configMap.main_html);
    setJqueryMap();
    
    // 우리 스키마를 사용하도록 uriAnchor 설정
    $.uriAnchor.configModule({
      schema_map : configMap.anchor_schema_map
    });
    // 모델 초기화
    spa.model.initModule();

    //각 모듈 설정 및 초기화
    spa.login.initModule($('.spa-shell-login_modal'));
    spa.search.initModule($('.spa-shell-search_modal'));
    spa.view.initModule($('.spa-shell-main-content'), $('.spa-shell-article_modal'), $('.spa-shell-main-nav'));
    spa.memo.initModule($('.spa-shell-memo'));
    spa.signup.initModule($('.spa-shell-signup_modal'));

    // 각종 핸들러 부착
    $('.spa-shell-head-detailed').on('click', onDetailedButtonClick);
    $('.spa-shell-head-acct').on('click', onAcctButtonClick);
    $('.spa-shell-head-login').on('click', onLoginButtonClick);
    $('.spa-memo-btn_slide_down').on('click', onMemoTitleClick);
    $('.spa-shell-memo h1').on('click', onMemoTitleClick); 
    $('.spa-login-btn-sign_up').on('click', onSignupButtonClick);
    $('.spa-shell-head-acct').on('click', onSearchButtonClick);
    $('.spa-shell-head-logo').on('click', function() {
      $(location).attr("href", "index.html");      
    });
    // login 체크
    loginCheck();

    // URI 앵커 변경 이벤트를 처리
    // 이 작업은 모든 기능 모듈이 설정 및 초기화 된 후에 수행한다.
    // 이렇게 하지 않으면 페이지 로드 시점에 앵커를 판단하는 데 사용되는
;    // 트리거 이벤트를 모듈에서 처리할 수 없게 된다.
    $(window)
      .bind('hashchange', onHashChange)
      .trigger('hashchange');
  };
  // /initModule/ End
  
  // /isModalActivated/ Start
  // 목적 : 현재 모달에 대한 상태를 반환
  // 반환값 : boolean
  //          - true : modal이 열려있음.
  //          - false : modal이 닫혀있음.
  isModalActivated = function() {
    return is_modal_activate;
  };
  // /isModalActivated/ End
  /*                           public method end                             */
  
  // Public 함수 개체 반환
  return  { 
            initModule : initModule,
            isModalActivated : isModalActivated,
            changeAnchorPart : changeAnchorPart,
            onCategoryClick : onCategoryClick
          };
}());
